#include <iostream>
#include <string>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef websocketpp::server<websocketpp::config::asio> wsserver_t;

void http_callback(wsserver_t *srv, websocketpp::connection_hdl hdl)
{
    // 给客户端返回一个hello world的页面
    // 先从获取一下通信连接对象
    // 使用get_con_from_hdl获取connection_hdl 对应连接的connection_ptr
    wsserver_t::connection_ptr conn = srv->get_con_from_hdl(hdl);
    // 打印一下请求正文，在connection对象中有个get_request_body方法就是获取请求正文内容的
    std::cout << "body: " << conn->get_request_body() << std::endl;
    // 获取一下请求信息的对象
    websocketpp::http::parser::request req = conn->get_request();
    // 打印一下请求方法
    std::cout << "method: " << req.get_method() << std::endl;
    // 打印一下请求的资源路径
    std::cout << "uri: " << req.get_uri() << std::endl;

    // 设置一下响应正文
    std::string body = "<html><body><h1> Hello world </h1></body></html>";
    conn->set_body(body);
    // 设置响应字段
    conn->append_header("Content-Type", "text/html");     // 文本类型
    conn->set_status(websocketpp::http::status_code::ok); // 状态码
}

void wsopen_callback(wsserver_t *srv, websocketpp::connection_hdl hdl)
{
    std::cout << "websocket 握手成功" << std::endl;
}

void wsclose_callback(wsserver_t *srv, websocketpp::connection_hdl hdl)
{
    std::cout << "websocket 连接断开" << std::endl;
}

void wsmessage_callback(wsserver_t *srv, websocketpp::connection_hdl hdl, wsserver_t::message_ptr msg)
{
    // 先从获取一下通信连接对象
    // 使用get_con_from_hdl获取connection_hdl 对应连接的connection_ptr
    wsserver_t::connection_ptr conn = srv->get_con_from_hdl(hdl);
    // 获取一下客户端给服务器发过来的消息数据
    // 使用 message_buffer空间中的get_payload函数来获取
    std::cout << "wsmsg: " << msg->get_payload() << std::endl;

    // 制作回响
    std::string resp = "client say: " + msg->get_payload();
    conn->send(resp, websocketpp::frame::opcode::text);
}

int main()
{
    // 使用 websocketpp 搭建服务器
    // 1. 实例化 server 对象
    wsserver_t wssrv;

    // 2. 设置日志输出等级
    // websocketpp::log::alevel::none表示禁止打印所有日志
    wssrv.set_access_channels(websocketpp::log::alevel::none);

    // 3. 初始化 asio 框架中的调度器
    // init_asio用于初始化asio框架中的io_service调度器
    wssrv.init_asio();
    // 启动地址重用
    wssrv.set_reuse_addr(true);

    // 4. 设置业务处理回调函数（具体业务处理的函数由我们自己实现）
    wssrv.set_http_handler(std::bind(http_callback, &wssrv, std::placeholders::_1));
    wssrv.set_open_handler(std::bind(wsopen_callback, &wssrv, std::placeholders::_1));
    wssrv.set_close_handler(std::bind(wsclose_callback, &wssrv, std::placeholders::_1));
    wssrv.set_message_handler(std::bind(wsmessage_callback, &wssrv, std::placeholders::_1, std::placeholders::_2));

    // 5. 设置服务器监听端口
    wssrv.listen(8080);

    // 6. 开始获取新建连接
    wssrv.start_accept();

    // 7. 启动服务器
    wssrv.run();

    return 0;
}